/*****************************************************************************/
/*!	\file		PIS10Handlers.c
 *	\brief		C Source code file for the YX-PIS Example
 *	\par		Dalian Yunxing Tech Co., Ltd.
 *
 *				Dalian, China
 *				Phone   : +86 (411) 8825 4852
 *				Email   : yx@yunxing.tech
 */
/*****************************************************************************/

#include <stdio.h>
#include <string.h>
#include "IEC61850Functions.h"
#include "IEC61850API.h"
#include "UserInput.h"
#include "PrintView.h"
#include "LocalData.h"
#include "PIS10CreateServerClient.h"


IEC61850_ErrorCode GetConnectionsList()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	ConnectionList connectionList = { 0 };

	result = IEC61850_GetConnectionsList(iec61850, &connectionList);
	if (result == S_OK) {
		printf("\nNum of connection: (%u)\n", connectionList.length);
		if (connectionList.length > 0) {
			U32 index = 0;
			char strError[SIZE_OF_ERROR_STRING] = { 0 };	/* Set the Error String to NONE */
			snprintf(strError, SIZE_OF_ERROR_STRING, "Get connected server list success.");	/* Set error message to show success */
			SetErrorString(strError, SIZE_OF_ERROR_STRING);

			/* Print the list */
			printf("\t[Index]\t[IP]\t\t[Status]\t[IED Name]\n");
			for (index = 0; index < connectionList.length; index++) {
				printf("\t%u\t%s\t%s\t%s\n",
					connectionList.connections[index].AAIndex,
					connectionList.connections[index].IPAddress,
					connectionList.connections[index].bConnectionState ? "Connected" : "Disconnected",
					connectionList.connections[index].iedName);
			}
		}
		/* Wait for user */
		printf("\nPress enter to continue.");
		getchar();
	} else {
		/* If the function failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "Get connected IED list failed: %i: %s\n", result, IEC61850_ErrorString(result) == NULL ? "Error" : IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}
	return result;
}

IEC61850_ErrorCode UpdateMMXUPhsAMagi(S32 newValue)
{
	IEC61850_ErrorCode result = S_OK;

	IEC61850_DataAttributeID daid = { 3, 0, 0, 0, 0 };
	IEC61850_DataAttributeData daData = { 0 };

	IEC61850 iec61850 = GetMyServerClient();

	/* Setup the Data Attribute Data Struct */
	daData.bitLength = sizeof(S32) * 8;	// set the size of the data in bits
	daData.type = IEC61850_DATATYPE_INT32;	// set the type of the data
	daData.pvData = &newValue;	// Set a pointer to the data

	/* Perform the Update */
	result = IEC61850_Update(iec61850, &daid, &daData, 1);	// count of 1 as only 1 element is being updated

	if (result == S_OK) {
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetMMXUPhsAMagi(newValue);
	} else {
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "UpdateMMXUPhsAMagi Update failed:(%i) %s\n", result, IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return result;
}

IEC61850_ErrorCode UpdateMMXUPhsBMagi(S32 newValue)
{
	IEC61850_ErrorCode result = S_OK;

	IEC61850_DataAttributeID daid = { 4, 0, 0, 0, 0 };
	IEC61850_DataAttributeData daData = { 0 };

	IEC61850 iec61850 = GetMyServerClient();

	/* Setup the Data Attribute Data Struct */
	daData.bitLength = sizeof(S32) * 8;	// set the size of the data in bits
	daData.type = IEC61850_DATATYPE_INT32;	// set the type of the data
	daData.pvData = &newValue;	// set a pointer to the data

	/* Perform the Update */
	result = IEC61850_Update(iec61850, &daid, &daData, 1);	// count of 1 as only 1 element is being updated

	if (result == S_OK) {
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetMMXUPhsBMagi(newValue);
	} else {
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "MMXUPhsBMagi Update failed:(%i) %s\n", result, IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return result;
}

IEC61850_ErrorCode UpdateMMXUPhsCMagi(S32 newValue)
{
	IEC61850_ErrorCode result = S_OK;

	IEC61850_DataAttributeID daid = { 5, 0, 0, 0, 0 };
	IEC61850_DataAttributeData daData = { 0 };

	IEC61850 iec61850 = GetMyServerClient();

	/* Setup the Data Attribute Data Struct */
	daData.bitLength = sizeof(S32) * 8;	// set the size of the data in bits
	daData.type = IEC61850_DATATYPE_INT32;	// set the type of the data
	daData.pvData = &newValue;	// set a pointer to the data

	result = IEC61850_Update(iec61850, &daid, &daData, 1);	// count of 1 as only 1 element is being updated

	if (result == S_OK) {
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetMMXUPhsCMagi(newValue);
	} else {
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "MMXUPhsCMagi Update failed:(%i) %s\n", result, IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return result;
}

IEC61850_ErrorCode UpdateTTNSTnsSv1Magf(Float32 newValue)
{
	IEC61850_ErrorCode result = S_OK;

	IEC61850_DataAttributeID daid = { 7, 0, 0, 0, 0 };
	IEC61850_DataAttributeData daData = { 0 };

	IEC61850 iec61850 = GetMyServerClient();

	/* Setup the Data Attribute Data Struct */
	daData.bitLength = sizeof(Float32) * 8;	// set the size of the data in bits
	daData.type = IEC61850_DATATYPE_FLOAT32;	// set the type of the data
	daData.pvData = &newValue;	// set a pointer to the data

	result = IEC61850_Update(iec61850, &daid, &daData, 1);	// count of 1 as only 1 element is being updated

	if (result == S_OK) {
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetTTNSTnsSv1Magf(newValue);
	} else {
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "UpdateTTNSTnsSv1Magf Update failed:(%i) %s\n", result, IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return result;
}

IEC61850_ErrorCode UpdateTTNSTnsSv2Magf(Float32 newValue)
{
	IEC61850_ErrorCode result = S_OK;

	IEC61850_DataAttributeID daid = { 7, 0, 0, 0, 1 };
	IEC61850_DataAttributeData daData = { 0 };

	IEC61850 iec61850 = GetMyServerClient();

	/* Setup the Data Attribute Data Struct */
	daData.bitLength = sizeof(Float32) * 8;	// set the size of the data in bits
	daData.type = IEC61850_DATATYPE_FLOAT32;	// set the type of the data
	daData.pvData = &newValue;	// set a pointer to the data

	result = IEC61850_Update(iec61850, &daid, &daData, 1);	// count of 1 as only 1 element is being updated

	if (result == S_OK) {
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetTTNSTnsSv2Magf(newValue);
	} else {
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "UpdateTTNSTnsSv2Magf Update failed:(%i) %s\n", result, IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return result;
}

IEC61850_ErrorCode UpdateTTNSTnsSv3Magf(Float32 newValue)
{
	IEC61850_ErrorCode result = S_OK;

	IEC61850_DataAttributeID daid = { 7, 0, 0, 0, 2 };
	IEC61850_DataAttributeData daData = { 0 };

	IEC61850 iec61850 = GetMyServerClient();

	/* Setup the Data Attribute Data Struct */
	daData.bitLength = sizeof(Float32) * 8;	// set the size of the data in bits
	daData.type = IEC61850_DATATYPE_FLOAT32;	// set the type of the data
	daData.pvData = &newValue;	// set a pointer to the data

	result = IEC61850_Update(iec61850, &daid, &daData, 1);	// count of 1 as only 1 element is being updated

	if (result == S_OK) {
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetTTNSTnsSv3Magf(newValue);
	} else {
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "UpdateTTNSTnsSv3Magf Update failed:(%i) %s\n", result, IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return result;
}

IEC61850_ErrorCode UpdatePDIFCrvPts(CrvPts newValue, S8 index, S8 xy)
{
	IEC61850_ErrorCode result = S_OK;

	IEC61850_DataAttributeID daid = { 6, (unsigned int)index, 0, 0, (unsigned int)xy };
	IEC61850_DataAttributeData daData = { 0 };
	IEC61850 iec61850 = GetMyServerClient();

	daData.arrayIndex = 0;
	daData.bitLength = 32;
	daData.type = IEC61850_DATATYPE_FLOAT32;
	if (xy == 0) {	// update xVal
		daData.pvData = &(newValue.xVal);
	} else if (xy == 1) {	// update yVal
		daData.pvData = &(newValue.yVal);
	}

	result = IEC61850_Update(iec61850, &daid, &daData, 1);

	if (result == S_OK) {
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Update Succeeded Update the local value for the gui*/
		SetPDIFCrvPts(index, newValue);
	} else {
		/* If the Update failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "PDIFCrvPtsYVal[%d] Update failed:(%i) %s\n", index, result, IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return result;
}

void ControlOperateDemo()
{
	char continueMainLoop = 'y';
	char usrCommand = 0;
	Boolean boolVal = FALSE;
	IEC61850_ErrorCode IEC61850Error = S_OK;
	do {
		PrintControlMenuView();

		usrCommand = GetCommIndexFromUser();

		switch (usrCommand) {
		case 0:
			continueMainLoop = 'n';
			break;
		case 1:
			/* Get a value from user */
			boolVal = GetBooleanFromUser();
			/* Do the Operate with the value*/
			OperateGGIO(boolVal, 1);
			break;
		case 2:
			/* Get a value from user */
			boolVal = GetBooleanFromUser();
			IEC61850Error = SelectGGIO();
			/* Do the Operate with the value*/
			OperateGGIO(boolVal, 2);
			break;
		case 3:
			/* Get a value from user */
			boolVal = GetBooleanFromUser();
			/* Do the Operate with the value*/
			OperateGGIO(boolVal, 3);
			break;
		case 4:
			/* Get a value from user */
			boolVal = GetBooleanFromUser();
			SelectGGIOWithVal(boolVal);
			/* Do the Operate with the value*/
			OperateGGIO(boolVal, 4);
			break;
		case 5:
			boolVal = GetBooleanFromUser();
			/* CSWI is SBO with enhanced Security so we need to do Select first with the value*/
			IEC61850Error = SelectCSWI(boolVal);
			if (IEC61850Error == S_OK) {
				/* Do the Operate with the value*/
				OperateCSWI(boolVal);
			}
			break;
		default:
			break;
		}

	} while (continueMainLoop == 'y');
}

void DataAccess()
{
	char continueMainLoop = 'y';
	char usrCommand = 0;
	do {
		PrintDataAccessMenuView();

		usrCommand = GetCommIndexFromUser();

		switch (usrCommand) {
		case 0:
			continueMainLoop = 'n';
			break;
		case 1:
			GetServerDir();
			break;
		case 2:
			GetLDDir();
			break;
		case 3:
			GetLNDir();
			break;
		case 4:
			GetAllDataValues();
			break;
		case 5:
			GetAllDataDefinition();
			break;
		case 6:
			GetAllCBValues();
			break;
		case 7:
			GetDataValues();
			break;
		case 8:
			SetDataValues();
			break;
		case 9:
			GetDataDirectory();
			break;
		case 10:
			GetDataDefinition();
			break;
		case 11:
			GetDataSetValues();
			break;
		case 12:
			SetDataSetValues();
			break;
		case 13:
			CreateDataSet();
			break;
		case 14:
			DeleteDataSet();
			break;
		case 15:
			GetDataSetDirectory();
			break;
		default:
			break;
		}

	} while (continueMainLoop == 'y');
}

void ReportOperate()
{
	char continueMainLoop = 'y';
	char usrCommand = 0;
	do {
		PrintReportMenuView();

		usrCommand = GetCommIndexFromUser();

		switch (usrCommand) {
		case 0:
			continueMainLoop = 'n';
			break;
		case 1:
			GetBufferedReportControlBlockValues();
			break;
		case 2:
			SetBufferedReportControlBlockValues();
			break;
		case 3:
			GetUnbufferedReportControlBlockValues();
			break;
		case 4:
			SetUnbufferedReportControlBlockValues();
			break;
		default:
			break;
		}
	} while (continueMainLoop == 'y');
}

void LogOperate()
{
	char continueMainLoop = 'y';
	S32 usrCommand = 0;
	do {
		PrintLogMenuView();
		usrCommand = GetCommIndexFromUser();
		switch (usrCommand) {
		case 0:
			continueMainLoop = 'n';
			break;
		case 1:
			GetLCBValues();
			break;
		case 2:
			SetLCBValues();
			break;
		case 3:
			QueryLogByTime();
			break;
		case 4:
			QueryLogAfter();
			break;
		case 5:
			GetLogStatusValues();
			break;
		default:
			break;
		}
	} while (continueMainLoop == 'y');
}

void GooseSVOperate()
{
	char continueMainLoop = 'y';
	char usrCommand = 0;
	do {
		PrintGooseAndSVMenuView();

		usrCommand = GetCommIndexFromUser();

		switch (usrCommand) {
		case 0:
			continueMainLoop = 'n';
			break;
		case 1:
			GetGoCBValues();
			break;
		case 2:
			SetGoCBValues();
			break;
		case 3:
			GetMSVCBValues();
			break;
		case 4:
			SetMSVCBValues();
			break;
		default:
			break;
		}

	} while (continueMainLoop == 'y');
}

void SettingGroupOperate()
{
	char continueMainLoop = 'y';
	char usrCommand = 0;
	do {
		PrintSettingGroupMenuView();

		usrCommand = GetCommIndexFromUser();

		switch (usrCommand) {
		case 0:
			continueMainLoop = 'n';
			break;
		case 1:
			GetEditSGValue();
			break;
		case 2:
			SelectActiveSG();
			break;
		case 3:
			SelectEditSG();
			break;
		case 4:
			SetEditSGValue();
			break;
		case 5:
			ConfirmEditSGValues();
			break;
		case 6:
			GetSGCBValues();
			break;
		default:
			break;
		}
	} while (continueMainLoop == 'y');
}

void FileOperate()
{
	char continueMainLoop = 'y';
	char usrCommand = 0;
	do {
		PrintFileMenuView();

		usrCommand = GetCommIndexFromUser();

		switch (usrCommand) {
		case 0:
			continueMainLoop = 'n';
			break;
		case 1:
			CMSGetFile();
			break;
		case 2:
			CMSSetFile();
			break;
		case 3:
			CMSDeleteFile();
			break;
		case 4:
			CMSGetFileAttributeValues();
			break;
		case 5:
			CMSGetFileDirectory();
			break;
		default:
			break;
		}

	} while (continueMainLoop == 'y');
}

void RPCAccess()
{
	char continueMainLoop = 'y';
	char usrCommand = 0;
	do {
		PrintRPCAccessMenuView();

		usrCommand = GetCommIndexFromUser();

		switch (usrCommand) {
		case 0:
			continueMainLoop = 'n';
			break;
		case 1:
			GetRpcInterfaceDirectory();
			break;
		case 2:
			GetRpcMethodDirectory();
			break;
		case 3:
			GetRpcInterfaceDefinition();
			break;
		case 4:
			GetRpcMethodDefinition();
			break;
		case 5:
			RpcCall();
			break;
		default:
			break;
		}
	} while (continueMainLoop == 'y');
}

IEC61850_ErrorCode SelectCSWI(Boolean ctlVal)
{
	IEC61850_ErrorCode result = S_OK;

	IEC61850_DataAttributeID daid = { 1, 0, 0, 0, 0 };
	IEC61850_DataAttributeData daData = { 0 };
	IEC61850_ControlParameters ctlParam = { 0 };

	IEC61850 iec61850 = GetMyServerClient();

	/* Setup the Data Attribute Data Struct */
	daData.bitLength = IEC61850_BOOLEAN_BITSIZE;	// set the size of the data in bits
	daData.type = IEC61850_DATATYPE_BOOLEAN;	// set the type of the data
	daData.pvData = &ctlVal;	// set a pointer to the data

	/* Perform the Select */
	result = IEC61850_ControlSelect(iec61850, &daid, &daData, &ctlParam);

	/* If the Select failed alert the user */
	if (result != S_OK) {
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "CSWI Select failed:(%i) %s\n", result, IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	} else {
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return result;
}

IEC61850_ErrorCode OperateCSWI(Boolean ctlVal)
{
	IEC61850_ErrorCode result = S_OK;

	IEC61850_DataAttributeID daid = { 1, 0, 0, 0, 0 };
	IEC61850_DataAttributeData daData = { 0 };
	IEC61850_ControlParameters ctlParam = { 0 };

	IEC61850 iec61850 = GetMyServerClient();

	/* Setup the Data Attribute Data Struct */
	daData.bitLength = IEC61850_BOOLEAN_BITSIZE;	// set the size of the data in bits
	daData.type = IEC61850_DATATYPE_BOOLEAN;	// set the type of the data
	daData.pvData = &ctlVal;	// set a pointer to the data

	/* Perform the Operate */
	result = IEC61850_ControlOperate(iec61850, &daid, &daData, &ctlParam);

	if (result == S_OK) {
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	} else {
		/* If the Operate failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "CSWI Operate failed:(%i) %s\n", result, IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return result;
}

IEC61850_ErrorCode SelectGGIO()
{
	IEC61850_ErrorCode result = S_OK;

	IEC61850_DataAttributeID daid = { 2, 0, 0, 0, 2 };
	IEC61850_ControlParameters ctlParam = { 0 };

	IEC61850 iec61850 = GetMyServerClient();

	/* Perform the Select */
	// Select by DAID
	result = IEC61850_ControlSelect(iec61850, &daid, NULL, &ctlParam);

	// // Select by sAddr
	// result = IEC61850_ControlSelectWithShortAddr(iec61850, "stVal@2.0.0.0.2", NULL, &ctlParam);

	/* If the Select failed alert the user */
	if (result != S_OK) {
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "GGIO Select failed:(%i) %s\n", result, IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	} else {
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return result;
}

IEC61850_ErrorCode SelectGGIOWithVal(Boolean ctlVal)
{
	IEC61850_ErrorCode result = S_OK;

	IEC61850_DataAttributeID daid = { 2, 0, 0, 0, 4 };
	IEC61850_DataAttributeData daData = { 0 };
	IEC61850_ControlParameters ctlParam = { 0 };

	IEC61850 iec61850 = GetMyServerClient();

	/* Setup the Data Attribute Data Struct */
	daData.bitLength = IEC61850_BOOLEAN_BITSIZE;	// set the size of the data in bits
	daData.type = IEC61850_DATATYPE_BOOLEAN;	// set the type of the data
	daData.pvData = &ctlVal;	// set a pointer to the data

	/* Perform the Select */
	// Select(SelectWithValue) by DAID
	result = IEC61850_ControlSelect(iec61850, &daid, &daData, &ctlParam);

	// // Select(SelectWithValue) by sAddr
	// result = IEC61850_ControlSelectWithShortAddr(iec61850, "stVal@2.0.0.0.4", &daData, &ctlParam);

	/* If the Select failed alert the user */
	if (result != S_OK) {
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "GGIO Select failed:(%i) %s\n", result, IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	} else {
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return result;
}

IEC61850_ErrorCode OperateGGIO(Boolean ctlVal, int index)
{
	IEC61850_ErrorCode result = S_OK;

	IEC61850_DataAttributeID daid = { 2, 0, 0, 0, index };
	IEC61850_DataAttributeData daData = { 0 };
	IEC61850_ControlParameters ctlParam = { 0 };

	IEC61850 iec61850 = GetMyServerClient();

	/* Setup the Data Attribute Data Struct */
	daData.bitLength = IEC61850_BOOLEAN_BITSIZE;	// set the size of the data in bits
	daData.type = IEC61850_DATATYPE_BOOLEAN;	// set the type of the data
	daData.pvData = &ctlVal;	// set a pointer to the data

	/* Perform the Operate */
	// Operate by DAID
	result = IEC61850_ControlOperate(iec61850, &daid, &daData, &ctlParam);

	// // Operate by sAddr
	// if (index == 1) {
	// 	result = IEC61850_ControlOperateWithShortAddr(iec61850, "stVal@2.0.0.0.1", &daData, &ctlParam);
	// } else if (index == 2) {
	// 	result = IEC61850_ControlOperateWithShortAddr(iec61850, "stVal@2.0.0.0.2", &daData, &ctlParam);
	// } else if (index == 3) {
	// 	result = IEC61850_ControlOperateWithShortAddr(iec61850, "stVal@2.0.0.0.3", &daData, &ctlParam);
	// } else if (index == 4) {
	// 	result = IEC61850_ControlOperateWithShortAddr(iec61850, "stVal@2.0.0.0.4", &daData, &ctlParam);
	// }

	if (result == S_OK) {
		/* Set the Error String to NONE */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		SetErrorString(strError, SIZE_OF_ERROR_STRING);

		/* If the Operate Succeeded Update the local value for the gui*/
	} else {
		/* If the Operate failed alert the user */
		char strError[SIZE_OF_ERROR_STRING] = { 0 };
		snprintf(strError, SIZE_OF_ERROR_STRING, "GGIO Operate failed:(%i) %s\n", result, IEC61850_ErrorString(result));
		SetErrorString(strError, SIZE_OF_ERROR_STRING);
	}

	return result;
}

IEC61850_ErrorCode GetServerDir()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetServerDirectory_Request request = { 0 };
	GetServerDirectory_Response response = { 0 };

	result = IEC61850_GetServerDirectory(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		PrintGetServerDirectoryResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetServerDirectory_Response(&response);

	return result;
}

IEC61850_ErrorCode GetLDDir()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetLogicalDeviceDirectory_Request request = { 0 };
	GetLogicalDeviceDirectory_Response response = { 0 };
	request.ldName = "ServerIEDExample";

	result = IEC61850_GetLogicalDeviceDirectory(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		PrintGetLogicalDeviceDirectoryResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetLogicalDeviceDirectory_Response(&response);
	return result;
}

IEC61850_ErrorCode GetLNDir()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetLogicalNodeDirectory_Request  request = { 0 };
	GetLogicalNodeDirectory_Response response = { 0 };
	unsigned int lnIndex = 0;
	struct StringList* lnRefList = StringListMalloc();
	U32 acsiClass = 0;

	StringListAdd(lnRefList, "ServerIEDExample");
	StringListAdd(lnRefList, "ServerIEDExample/LLN0");
	StringListAdd(lnRefList, "ServerIEDExample/CSWI0");
	StringListAdd(lnRefList, "ServerIEDExample/GGIO0");
	StringListAdd(lnRefList, "ServerIEDExample/MMXU0");
	StringListAdd(lnRefList, "ServerIEDExample/PDIF0");
	StringListAdd(lnRefList, "ServerIEDExample/IARC0");

	if (lnRefList->length <= 0) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	printf("LN Reference and LD Name List:\n");
	PrintStringList(lnRefList);
	printf("Please select LN ref:\n");

	lnIndex = GetIndexFromUser();

	printf("Please select the ACSIClass from:\n");
	printf("  1. DataObject\n");
	printf("  2. DATA-SET\n");
	printf("  3. BRCB\n");
	printf("  4. URCB\n");
	printf("  5. LCB\n");
	printf("  6. LOG\n");
	printf("  7. SGCB\n");
	printf("  8. GoCB\n");
	printf(" 10. MSVCB\n");
	acsiClass = GetIndexFromUser();
	printf("\n");

	request.reference = "";
	if (lnIndex >= 1 && lnIndex <= lnRefList->length) {
		request.reference = lnRefList->list[lnIndex - 1];
	}
	request.acsiClass = (enum IEC61850_ACSIClass)acsiClass;
	result = IEC61850_GetLogicalNodeDirectory(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		PrintGetLogicalNodeDirectoryResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetLogicalNodeDirectory_Response(&response);
	FreeStringList(lnRefList);
	return result;
}

IEC61850_ErrorCode GetAllDataValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetAllData_Request request = { 0 };
	GetAllDataValues_Response response = { 0 };
	int i = 0;
	unsigned int lnIndex = 0;
	unsigned int fcIndex = 0;
	char FC[13][3] = { "ST","MX","SP","SV","CF","DC","SG","SE","SR","OR","BL","EX","XX" };
	struct StringList* lnRefList = StringListMalloc();

	StringListAdd(lnRefList, "ServerIEDExample");
	StringListAdd(lnRefList, "ServerIEDExample/LLN0");
	StringListAdd(lnRefList, "ServerIEDExample/CSWI0");
	StringListAdd(lnRefList, "ServerIEDExample/GGIO0");
	StringListAdd(lnRefList, "ServerIEDExample/MMXU0");
	StringListAdd(lnRefList, "ServerIEDExample/PDIF0");
	StringListAdd(lnRefList, "ServerIEDExample/IARC0");
	if (lnRefList->length <= 0) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	printf("LN Reference List:\n");
	PrintStringList(lnRefList);
	printf("Please select LN ref:\n");
	lnIndex = GetIndexFromUser();


	printf("FC List:\n");
	for (i = 0; i < 13; i++) {
		printf("%d.%s\n", i + 1, FC[i]);
	}
	fcIndex = GetIndexFromUser();

	request.reference = "";
	if (lnIndex >= 1 && lnIndex <= lnRefList->length) {
		request.reference = lnRefList->list[lnIndex - 1];
	}
	request.fc = "XX";
	if (fcIndex >= 1 && fcIndex <= 13) {
		request.fc = FC[fcIndex - 1];
	}
	result = IEC61850_GetAllDataValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		PrintGetAllDataValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetAllDataValues_Response(&response);
	FreeStringList(lnRefList);
	return result;
}

IEC61850_ErrorCode GetAllDataDefinition()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetAllData_Request request = { 0 };
	GetAllDataDefinition_Response response = { 0 };
	int i = 0;
	unsigned int lnIndex = 0;
	unsigned int fcIndex = 0;
	char FC[13][3] = { "ST","MX","SP","SV","CF","DC","SG","SE","SR","OR","BL","EX","XX" };
	struct StringList* lnRefList = StringListMalloc();

	StringListAdd(lnRefList, "ServerIEDExample");
	StringListAdd(lnRefList, "ServerIEDExample/LLN0");
	StringListAdd(lnRefList, "ServerIEDExample/CSWI0");
	StringListAdd(lnRefList, "ServerIEDExample/GGIO0");
	StringListAdd(lnRefList, "ServerIEDExample/MMXU0");
	StringListAdd(lnRefList, "ServerIEDExample/PDIF0");
	StringListAdd(lnRefList, "ServerIEDExample/IARC0");
	if (lnRefList->length <= 0) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	printf("LN Reference List:\n");
	PrintStringList(lnRefList);
	printf("Please select LN ref:\n");

	lnIndex = GetIndexFromUser();

	printf("FC List:\n");
	for (i = 0; i < 13; i++) {
		printf("%d.%s\n", i + 1, FC[i]);
	}

	fcIndex = GetIndexFromUser();

	request.reference = "";
	if (lnIndex >= 1 && lnIndex <= lnRefList->length) {
		request.reference = lnRefList->list[lnIndex - 1];
	}
	request.fc = "XX";
	if (fcIndex >= 1 && fcIndex <= 13) {
		request.fc = FC[fcIndex - 1];
	}
	result = IEC61850_GetAllDataDefinition(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		PrintGetAllDataDefinitionResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeDataDefinitions(&response.data);
	FreeStringList(lnRefList);
	return result;
}

IEC61850_ErrorCode GetAllCBValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetAllCBValues_Request request = { 0 };
	GetAllCBValues_Response response = { 0 };
	enum IEC61850_ACSIClass acsiClass = ACSI_CLASS_RESERVED;
	int loopCount = 0;
	unsigned int lnIndex = 0;

	struct StringList* lnList = StringListMalloc();
	StringListAdd(lnList, "ServerIEDExample");
	StringListAdd(lnList, "ServerIEDExample/LLN0");
	StringListAdd(lnList, "ServerIEDExample/CSWI0");
	StringListAdd(lnList, "ServerIEDExample/GGIO0");
	StringListAdd(lnList, "ServerIEDExample/MMXU0");
	StringListAdd(lnList, "ServerIEDExample/PDIF0");
	StringListAdd(lnList, "ServerIEDExample/IARC0");

	if (lnList->length <= 0) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	printf("Logical Node List:\n");
	PrintStringList(lnList);
	printf("Please select LN ref:\n");

	lnIndex = GetIndexFromUser();

	do {
		loopCount = loopCount % 3;
		if (loopCount == 0) {
			printf("Please select the ACSIClass from:\n");
			printf("  3. BRCB\n");
			printf("  4. URCB\n");
			printf("  5. LCB\n");
			printf("  7. SGCB\n");
			printf("  8. GoCB\n");
			printf(" 10. MSVCB\n");
		}
		acsiClass = (enum IEC61850_ACSIClass)GetIndexFromUser();
		printf("\n");
		loopCount++;
	} while (acsiClass != 3 && acsiClass != 4 && acsiClass != 5 && acsiClass != 7 && acsiClass != 8 && acsiClass != 10);

	request.reference = "";
	if (lnIndex >= 1 && lnIndex <= lnList->length) {
		request.reference = lnList->list[lnIndex - 1];
	}
	request.acsiClass = acsiClass;
	result = IEC61850_GetAllCBValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		PrintGetAllCBValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeAllCBValues(&response.cbValue);
	FreeStringList(lnList);
	return result;
}

IEC61850_ErrorCode GetDataValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	struct GetDataValues_Request request = { 0 };
	struct GetDataValues_Response response = { 0 };
	unsigned int dataIndex = 0;
	unsigned int fcIndex = 0;
	struct StringList* dataRefList = StringListMalloc();
	char FC[13][3] = { "ST","MX","SP","SV","CF","DC","SG","SE","SR","OR","BL","EX","XX" };

	StringListAdd(dataRefList, "ServerIEDExample/LLN0.Mod");
	StringListAdd(dataRefList, "ServerIEDExample/MMXU0.A");
	StringListAdd(dataRefList, "ServerIEDExample/CSWI0.errorReference");
	StringListAdd(dataRefList, "ServerIEDExample/GGIO0.NumSubIntv.minVal");
	if (dataRefList->length <= 0) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	printf("Data Ref List:\n");
	PrintStringList(dataRefList);
	printf("Please select data ref:\n");
	dataIndex = GetIndexFromUser();

	request.data.size = 1;
	request.data.FCDAs = calloc(1, sizeof(FCDA));
	if (request.data.FCDAs == NULL) {
		FreeStringList(dataRefList);
		return IEC61850_ERROR_NO_MEMORY;
	}
	if (dataIndex >= 1 && dataIndex <= dataRefList->length) {
		strcpy(request.data.FCDAs->DARef, dataRefList->list[dataIndex - 1]);
	}

	fcIndex = 12;
	strncpy(request.data.FCDAs->FC, FC[fcIndex], 3);

	result = IEC61850_GetDataValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		PrintGetDataValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetDataValues_Response(&response);

	// free the dynamically allocated memory of 'request'.
	free(request.data.FCDAs);
	request.data.FCDAs = NULL;
	FreeStringList(dataRefList);

	return result;
}

IEC61850_ErrorCode SetDataValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	SetDataValues_Request request = { 0 };
	SetDataValues_Response response = { 0 };
	char* ref = "ServerIEDExample/GGIO0.NumSubIntv.minVal";
	S32 newVal = 0;

	request.dataNum = 1;
	request.fcdaVals = calloc(1, sizeof(FCDAVals));
	if (request.fcdaVals == NULL) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	printf("Will set data: [%s]\nPlease input new data value:\n", ref);
	newVal = GetInteger32FromUser();

	strncpy(request.fcdaVals->dataRef, ref, OBJECT_REFERENCE_STRING_LEN);
	strncpy(request.fcdaVals->FC, "CF", FC_LEN);
	request.fcdaVals->dataAttributes.type = IEC61850_DATATYPE_INT32; 
	request.fcdaVals->dataAttributes.bitLength = 32;
	request.fcdaVals->dataAttributes.pvData = &newVal;

	result = IEC61850_SetDataValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		unsigned int i = 0;
		printf("request:\n");
		for (i = 0; i < request.dataNum; i++) {
			printf("data[%u]:\n  reference: [%s]\n  fc: [%s]\n  value:\n", i + 1, request.fcdaVals[i].dataRef, request.fcdaVals[i].FC);
			PrintDataValue(&request.fcdaVals->dataAttributes, 2, FALSE);
		}
		printf("response:\n");
		PrintSetDataValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeSetDataValues_Response(&response);

	// free the dynamically allocated memory of 'request'.
	free(request.fcdaVals);
	request.fcdaVals = NULL;

	return result;
}

IEC61850_ErrorCode GetDataDirectory()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetDataDirectory_Request request = { 0 };
	GetDataDirectory_Response response = { 0 };
	unsigned int dataIndex = 0;
	struct StringList* dataRefList = StringListMalloc();

	StringListAdd(dataRefList, "ServerIEDExample/LLN0.Mod");
	StringListAdd(dataRefList, "ServerIEDExample/MMXU0.A");
	StringListAdd(dataRefList, "ServerIEDExample/CSWI0.Pos");
	StringListAdd(dataRefList, "ServerIEDExample/PDIF0.TmASt");
	StringListAdd(dataRefList, "P_L2201APLD0/LLN0.Mod");
	StringListAdd(dataRefList, "P_L2201APPROT/FOCH1PSCH1.ProTx");
	if (dataRefList->length <= 0) {
		return S_OK;
	}

	printf("Data Ref List:\n");
	PrintStringList(dataRefList);
	printf("Please select data ref:\n");

	dataIndex = GetIndexFromUser();

	request.dataReference = "";
	if (dataIndex >= 1 && dataIndex <= dataRefList->length) {
		request.dataReference = dataRefList->list[dataIndex - 1];
	}
	request.referenceAfter = NULL;
	result = IEC61850_GetDataDirectory(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		PrintGetDataDirectoryResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeStringList(dataRefList);
	FreeGetDataDirectory_Response(&response);
	return result;
}

IEC61850_ErrorCode GetDataDefinition()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetDataDefinition_Request request = { 0 };
	GetDataDefinition_Response response = { 0 };
	unsigned int dataIndex = 0;
	unsigned int fcIndex = 0;
	char FC[13][3] = { "ST","MX","SP","SV","CF","DC","SG","SE","SR","OR","BL","EX","XX" };
	struct StringList* dataRefList = StringListMalloc();

	StringListAdd(dataRefList, "ServerIEDExample/MMXU0.A");
	StringListAdd(dataRefList, "ServerIEDExample/PDIF0.TmASt");
	StringListAdd(dataRefList, "ServerIEDExample/QFVR0.VarStr");
	StringListAdd(dataRefList, "ServerIEDExample/NHAS.nohas");
	if (dataRefList->length <= 0) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	printf("Data Ref List:\n");
	PrintStringList(dataRefList);
	printf("Please select data reference:\n");
	dataIndex = GetIndexFromUser();

	request.data.size = 1;
	request.data.FCDAs = calloc(1, sizeof(FCDA));
	if (request.data.FCDAs == NULL) {
		FreeStringList(dataRefList);
		return IEC61850_ERROR_NO_MEMORY;
	}
	if (dataIndex >= 1 && dataIndex <= dataRefList->length) {
		strcpy(request.data.FCDAs->DARef, dataRefList->list[dataIndex - 1]);
	}

	fcIndex = 12;
	strncpy(request.data.FCDAs->FC, FC[fcIndex], FC_LEN);

	result = IEC61850_GetDataDefinition(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		PrintGetDataDefinitionResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}

	FreeGetDataDefinition_Response(&response);

	// free the dynamically allocated memory of 'request'.
	free(request.data.FCDAs);
	request.data.FCDAs = NULL;
	FreeStringList(dataRefList);

	return result;
}

IEC61850_ErrorCode CreateDataSet()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	CreateDataSet_Request request = { 0 };
	eServiceError serviceError = SERVICE_ERROR_NO_ERROR;
	FCDA fcdaList[2] = { 0 };
	unsigned int i = 0;

	request.datasetReference = "ServerIEDExample/LLN0.PersistentDS";
	request.fcdaList = fcdaList;
	request.numOfFcda = 2;

	strncpy(fcdaList[0].DARef, "ServerIEDExample/LLN0.Beh.stVal", OBJECT_REFERENCE_STRING_LEN);
	strncpy(fcdaList[1].DARef, "ServerIEDExample/LPHD0.Beh.stVal", OBJECT_REFERENCE_STRING_LEN);
	strncpy(fcdaList[0].FC, "ST", FC_LEN);
	strncpy(fcdaList[1].FC, "ST", FC_LEN);

	result = IEC61850_CreateDataSet(iec61850, serverIndex, &request, &serviceError);
	if (result == S_OK) {
		printf("request:\n  datasetReference: [%s]\n", request.datasetReference);
		if (request.referenceAfter) {
			printf("  referenceAfter: [%s]\n", request.referenceAfter);
		}
		for (i = 0; i < request.numOfFcda; i++) {
			printf("  memberData[%d]:\n    reference: [%s]\n    fc: [%s]\n", i + 1, request.fcdaList[i].DARef, request.fcdaList[i].FC);
		}
		printf("\n");
		if (serviceError == SERVICE_ERROR_NO_ERROR) {
			printf("response:\nResponse+\n");
		} else {
			printf("response:\nResponse-\n  ServiceError: (%d) %s\n", serviceError, TranslateServiceError(serviceError));
		}
	} else {
		printf("result:[%d]\n", result);
	}

	return result;
}

IEC61850_ErrorCode DeleteDataSet()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	eServiceError serviceError = SERVICE_ERROR_NO_ERROR;
	char* datasetReference = "ServerIEDExample/LLN0.PersistentDS";

	result = IEC61850_DeleteDataSet(iec61850, serverIndex, datasetReference, &serviceError);
	if (result == S_OK) {
		printf("request:\n  datasetReference: [%s]\n\n", datasetReference);
		if (serviceError == SERVICE_ERROR_NO_ERROR) {
			printf("response:\nResponse+\n");
		} else {
			printf("response:\nResponse-\n  ServiceError: (%d) %s\n", serviceError, TranslateServiceError(serviceError));
		}
	} else {
		printf("result:[%d]\n", result);
	}

	return result;
}

IEC61850_ErrorCode GetDataSetDirectory()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetDataSetDirectory_Request request = { 0 };
	GetDataSetDirectory_Response response = { 0 };
	unsigned int dataIndex = 0;
	struct StringList* dataRefList = StringListMalloc();
	StringListAdd(dataRefList, "ServerIEDExample/LLN0.logDS");
	StringListAdd(dataRefList, "ServerIEDExample/LLN0.GooseDS");
	StringListAdd(dataRefList, "ServerIEDExample/GGIO0.UnbufferedDS");
	StringListAdd(dataRefList, "ServerIEDExample/LLN0.PersistentDS");
	if (dataRefList->length <= 0) {
		return IEC61850_ERROR_NO_MEMORY;
	}
	printf("dataset reference list:\n");
	PrintStringList(dataRefList);
	printf("Please select dataset reference:\n");

	dataIndex = GetIndexFromUser();

	request.datasetReference = "";
	if (dataIndex >= 1 && dataIndex <= dataRefList->length) {
		request.datasetReference = dataRefList->list[dataIndex - 1];
	}
	request.referenceAfter = NULL;
	if (dataIndex == 2) {
		request.referenceAfter = "ServerIEDExample/CSWI0.Pos.stVal";
	}

	result = IEC61850_GetDataSetDirectory(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n  datasetReference: [%s]\n", request.datasetReference);
		if (request.referenceAfter) {
			printf("  referenceAfter: [%s]\n", request.referenceAfter);
		}
		printf("\nresponse:\n");
		PrintGetDataSetDirectoryResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetDataSetDirectory_Response(&response);
	FreeStringList(dataRefList);
	return result;
}

IEC61850_ErrorCode GetDataSetValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetDataSetValues_Request request = { 0 };
	GetDataSetValues_Response response = { 0 };
	unsigned int dataIndex = 0;
	struct StringList* dataRefList = StringListMalloc();
	StringListAdd(dataRefList, "ServerIEDExample/LLN0.logDS");
	StringListAdd(dataRefList, "ServerIEDExample/LLN0.GooseDS");
	StringListAdd(dataRefList, "ServerIEDExample/GGIO0.UnbufferedDS");
	StringListAdd(dataRefList, "ServerIEDExample/LLN0.PersistentDS");

	if (dataRefList->length <= 0) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	printf("Dataset Ref List:\n");
	PrintStringList(dataRefList);
	printf("Please select dataset ref:\n");
	dataIndex = GetIndexFromUser();

	request.datasetReference = "";
	if (dataIndex >= 1 && dataIndex <= dataRefList->length) {
		request.datasetReference = dataRefList->list[dataIndex - 1];
	}
	request.referenceAfter = NULL;

	result = IEC61850_GetDataSetValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		PrintGetDataSetValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetDataSetValues_Response(&response);
	FreeStringList(dataRefList);
	return result;
}

IEC61850_ErrorCode SetDataSetValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	SetDataSetValues_Request request = { 0 };
	SetDataSetValues_Response response = { 0 };
	char dbpos = IEC61850_DB_POS_TRUE;
	IEC61850_TimeStamp t = { 0 };
	unsigned int i = 0;

	request.datasetReference = "ServerIEDExample/CSWI0.BufferedDS";
	request.referenceAfter = NULL;
	request.value.length = 2;
	request.value.dataAttributes = calloc(2, sizeof(IEC61850_DataAttributeData));
	if (request.value.dataAttributes == NULL) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	request.value.dataAttributes[0].bitLength = 2;
	request.value.dataAttributes[0].type = IEC61850_DATATYPE_CODED_ENUM;
	request.value.dataAttributes[0].pvData = &dbpos;

	IEC61850_GetTime(NULL, &t);
	request.value.dataAttributes[1].bitLength = IEC61850_TIMESTAMP_BITSIZE;
	request.value.dataAttributes[1].type = IEC61850_DATATYPE_TIMESTAMP;
	request.value.dataAttributes[1].pvData = &t;

	result = IEC61850_SetDataSetValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n  datasetReference: [%s]\n", request.datasetReference);
		if (request.referenceAfter) {
			printf("  referenceAfter: [%s]\n", request.referenceAfter);
		}
		for (i = 0; i < request.value.length; i++) {
			printf("  memberValue[%d]:\n", i + 1);
			PrintDataValue(&(request.value.dataAttributes[i]), 2, FALSE);
		}
		PrintSetDataSetValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeSetDataSetValues_Response(&response);

	// free the dynamically allocated memory of 'request'.
	free(request.value.dataAttributes);
	request.value.dataAttributes = NULL;

	return result;
}

IEC61850_ErrorCode GetBufferedReportControlBlockValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetBRCBValues_Request request = { 0 };
	GetBRCBValues_Response response = { 0 };
	request.number = 3;
	request.reference = calloc(request.number, sizeof(char*));
	if (request.reference) {
		request.reference[0] = "ServerIEDExample/CSWI0.BufferedCB01";
		request.reference[1] = "ServerIEDExample/CSWI0.BufferedCB02";
		request.reference[2] = "ServerIEDExample/CSWI0.BufferedCB03";

		result = IEC61850_GetBRCBValues(iec61850, serverIndex, &request, &response);
		if (result == S_OK) {
			unsigned int i = 0;
			printf("request:\n");
			for (i = 0; i < request.number; i++) {
				printf("\tbrcbReference[%u]: %s\n", i + 1, request.reference[i]);
			}
			printf("\nresponse:\n");
			PrintGetBRCBValuesResponse(&response);
		} else {
			printf("result:[%d]\n", result);
		}
		FreeGetBRCBValues_Response(&response);

		// free the dynamically allocated memory of 'request'.
		free(request.reference);
	}

	return result;
}

IEC61850_ErrorCode SetBufferedReportControlBlockValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	SetBRCBValues_Request request = { 0 };
	SetBRCBValues_Response response = { 0 };

	request.numOfRptCB = 1;
	request.brcbValsList = calloc(request.numOfRptCB, sizeof(tSetBRCBValues));
	if (request.brcbValsList) {
		Boolean rptEna = TRUE;
		request.brcbValsList[0].reference = "ServerIEDExample/CSWI0.BufferedCB01";
		request.brcbValsList[0].rptEna = &rptEna;
		printf("Will set [rptEna] for \"ServerIEDExample/CSWI0.BufferedCB01\"\n");
		rptEna = GetBooleanFromUser();

		result = IEC61850_SetBRCBValues(iec61850, serverIndex, &request, &response);
		if (result == S_OK) {
			PrintSetBRCBValuesResponse(&response);
		} else {
			printf("result:[%d]\n", result);
		}
		FreeSetBRCBValues_Response(&response);

		// free the dynamically allocated memory of 'request'.
		free(request.brcbValsList);
	} else {
		result = IEC61850_ERROR_NO_MEMORY;
	}
	return result;
}

IEC61850_ErrorCode GetUnbufferedReportControlBlockValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetURCBValues_Request request = { 0 };
	GetURCBValues_Response response = { 0 };

	request.number = 3;
	request.reference = calloc(request.number, sizeof(char*));
	if (request.reference == NULL) {
		result = IEC61850_ERROR_NO_MEMORY;
	} else {
		request.reference[0] = "ServerIEDExample/GGIO0.UnbufferedCB01";
		request.reference[1] = "ServerIEDExample/GGIO0.UnbufferedCB02";
		request.reference[2] = "ServerIEDExample/GGIO0.UnbufferedCB03";

		result = IEC61850_GetURCBValues(iec61850, serverIndex, &request, &response);
		if (result == S_OK) {
			unsigned int i = 0;
			printf("request:\n");
			for (i = 0; i < request.number; i++) {
				printf("\turcbReference[%u]: %s\n", i + 1, request.reference[i]);
			}
			printf("\nresponse:\n");
			PrintGetURCBValuesResponse(&response);
		} else {
			printf("result:[%d]\n", result);
		}
		FreeGetURCBValues_Response(&response);

		// free the dynamically allocated memory of 'request'.
		free(request.reference);
	}
	return result;
}

IEC61850_ErrorCode SetUnbufferedReportControlBlockValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	SetURCBValues_Request request = { 0 };
	SetURCBValues_Response response = { 0 };

	request.numOfRptCB = 1;
	request.urcbValsList = calloc(request.numOfRptCB, sizeof(tSetURCBValues));
	if (request.urcbValsList) {
		Boolean rptEna = TRUE;
		request.urcbValsList[0].reference = "ServerIEDExample/GGIO0.UnbufferedCB01";
		request.urcbValsList[0].rptEna = &rptEna;
		printf("Will set [rptEna] for \"ServerIEDExample/GGIO0.UnbufferedCB01\"\n");
		rptEna = GetBooleanFromUser();

		result = IEC61850_SetURCBValues(iec61850, serverIndex, &request, &response);
		if (result == S_OK) {
			PrintSetURCBValuesResponse(&response);
		} else {
			printf("result:[%d]\n", result);
		}
		FreeSetURCBValues_Response(&response);

		// free the dynamically allocated memory of 'request'.
		free(request.urcbValsList);
	} else {
		result = IEC61850_ERROR_NO_MEMORY;
	}
	return result;
}

IEC61850_ErrorCode GetLCBValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetLCBValues_Request request = { 0 };
	GetLCBValues_Response response = { 0 };

	request.number = 1;
	request.reference = calloc(request.number, sizeof(char*));
	if (request.reference == NULL) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	request.reference[0] = "ServerIEDExample/LLN0.logCBName";

	result = IEC61850_GetLCBValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		unsigned int i = 0;
		printf("request:\n");
		for (i = 0; i < request.number; i++) {
			printf("\tlcbReference[%u]: %s\n", i + 1, request.reference[i]);
		}
		printf("\nresponse:\n");
		PrintGetLCBValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetLCBValues_Response(&response);

	// free the dynamically allocated memory of 'request'.
	free(request.reference);

	return result;
}

IEC61850_ErrorCode SetLCBValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	SetLCBValues_Request request = { 0 };
	SetLCBValues_Response response = { 0 };

	request.lcb.length = 1;
	request.lcb.list = calloc(request.lcb.length, sizeof(tSetLCBValues));
	if (request.lcb.list == NULL) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	request.lcb.list[0].setFlag[SET_LCB_REQ_LOG_ENA] = 1;
	strcpy(request.lcb.list[0].lcbRef, "ServerIEDExample/LLN0.logCBName");
	printf("\nPlease set \"logEna\" for LCB \"ServerIEDExample/LLN0.logCBName\",\n");
	request.lcb.list[0].lcbValues.logEna = GetBooleanFromUser();

	result = IEC61850_SetLCBValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n");
		PrintSetLCBValues(&request.lcb);
		printf("response:\n");
		PrintSetLCBValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeSetLCBValues_Response(&response);

	// free the dynamically allocated memory of 'request'.
	if (request.lcb.list) {
		free(request.lcb.list);
	}

	return result;
}

IEC61850_ErrorCode QueryLogByTime()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	QueryLogByTime_Request request = { 0 };
	QueryLogByTime_Response response = { 0 };

	request.logReference = "ServerIEDExample/LLN0.logName";

	printf("Please specify the startTime (YYYYMMDDhhmmss): ");
	request.startTime = GetIEC61850TimeFromUser();

	printf("Please specify the stopTime (YYYYMMDDhhmmss): ");
	request.stopTime = GetIEC61850TimeFromUser();

	result = IEC61850_QueryLogByTime(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n");
		printf("\tlogReference: [%s]\n", request.logReference);
		if (request.startTime) {
			printf("\tstartTime:    ");
			PrintTimeStamp(request.startTime);
		}
		if (request.stopTime) {
			printf("\tstopTime:     ");
			PrintTimeStamp(request.stopTime);
		}
		if (request.entryAfter) {
			printf("\tentryAfter:   [%llu]", *request.entryAfter);
		}
		printf("\nresponse:\n");
		PrintQueryLogByTimeResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeQueryLogByTime_Response(&response);

	// free the dynamically allocated memory of 'request'.
	if (request.startTime) {
		free(request.startTime);
		request.startTime = NULL;
	}
	if (request.stopTime) {
		free(request.stopTime);
		request.stopTime = NULL;
	}

	return result;
}

IEC61850_ErrorCode QueryLogAfter()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	QueryLogAfter_Request request = { 0 };
	QueryLogAfter_Response response = { 0 };
	S32 entryId = 0;

	request.logReference = "ServerIEDExample/LLN0.logName";

	printf("Please specify the startTime (YYYYMMDDhhmmss): ");
	request.startTime = GetIEC61850TimeFromUser();

	printf("Please specify the entryID, ");
	entryId = GetInteger32FromUser();
	request.entry = (U64)entryId;

	result = IEC61850_QueryLogAfter(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n");
		printf("\tlogReference: [%s]\n", request.logReference);
		if (request.startTime) {
			printf("\tstartTime:    ");
			PrintTimeStamp(request.startTime);
		}
		printf("\tentry:        [%llu]\n\n", request.entry);
		printf("response:\n");
		PrintQueryLogAfterResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeQueryLogAfter_Response(&response);

	// free the dynamically allocated memory of 'request'.
	if (request.startTime) {
		free(request.startTime);
		request.startTime = NULL;
	}

	return result;
}

IEC61850_ErrorCode GetLogStatusValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetLogStatusValues_Request request = { 0 };
	GetLogStatusValues_Response response = { 0 };

	request.number = 1;
	request.reference = calloc(request.number, sizeof(char*));
	if (request.reference == NULL) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	request.reference[0] = "ServerIEDExample/LLN0.logName";

	result = IEC61850_GetLogStatusValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		unsigned int i = 0;
		printf("request:\n");
		for (i = 0; i < request.number; i++) {
			printf("\tlogReference[%u]: [%s]\n", i + 1, request.reference[i]);
		}
		printf("\nresponse:\n");
		PrintGetLogStatusValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetLogStatusValues_Response(&response);

	// free the dynamically allocated memory of 'request'.
	free(request.reference);

	return result;
}

IEC61850_ErrorCode GetGoCBValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetGoCBValues_Request request = { 0 };
	GetGoCBValues_Response response = { 0 };

	request.number = 2;
	request.reference = calloc(request.number, sizeof(char*));
	if (request.reference == NULL) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	request.reference[0] = "ServerIEDExample/LLN0.GooseCB";
	request.reference[1] = "ServerIEDExample/LLN0.GoCB";

	result = IEC61850_GetGoCBValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		unsigned int i = 0;
		printf("request:\n");
		for (i = 0; i < request.number; i++) {
			printf("\tgocbReference[%u]: [%s]\n", i + 1, request.reference[i]);
		}
		printf("\nresponse:\n");
		PrintGetGoCBValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetGoCBValues_Response(&response);

	// free the dynamically allocated memory of 'request'.
	free(request.reference);

	return result;
}

IEC61850_ErrorCode SetGoCBValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	SetGoCBValues_Request request = { 0 };
	SetGoCBValues_Response response = { 0 };

	request.number = 1;
	request.list = calloc(request.number, sizeof(tSetGoCBValues));
	if (request.list == NULL) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	strcpy(request.list[0].ref, "ServerIEDExample/LLN0.GooseCB");
	request.list[0].setFlag[SET_GOCB_FLAG_GO_ENA] = 1;
	request.list[0].goEna = FALSE;
	request.list[0].setFlag[SET_GOCB_FLAG_GO_ID] = 1;
	strcpy(request.list[0].goID, "goID");
	request.list[0].setFlag[SET_GOCB_FLAG_DAT_SET] = 1;
	strcpy(request.list[0].datSet, "ServerIEDExample/LLN0.GooseDS");

	result = IEC61850_SetGoCBValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		unsigned int i = 0;
		printf("request:\n");

		PrintSetGoCBValues(&request);

		printf("\nresponse:\n");
		PrintSetGoCBValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeSetGoCBValues_Response(&response);

	// free the dynamically allocated memory of 'request'.
	free(request.list);

	return result;
}

IEC61850_ErrorCode GetMSVCBValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetMSVCBValues_Request request = { 0 };
	GetMSVCBValues_Response response = { 0 };

	request.number = 2;
	request.reference = calloc(request.number, sizeof(char*));
	if (request.reference == NULL) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	request.reference[0] = "ServerIEDExample/LLN0.svcb";
	request.reference[1] = "ServerIEDExample/LLN0.testSVCBName";

	result = IEC61850_GetMSVCBValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		unsigned int i = 0;
		printf("request:\n");
		for (i = 0; i < request.number; i++) {
			printf("\treference[%u]: [%s]\n", i + 1, request.reference[i]);
		}
		printf("\nresponse:\n");
		PrintGetMSVCBValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetMSVCBValues_Response(&response);

	// free the dynamically allocated memory of 'request'.
	free(request.reference);

	return result;
}

IEC61850_ErrorCode SetMSVCBValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	SetMSVCBValues_Request request = { 0 };
	SetMSVCBValues_Response response = { 0 };

	request.length = 1;
	request.list = calloc(request.length, sizeof(tSetMSVCBValues));
	if (request.list == NULL) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	strcpy(request.list[0].ref, "ServerIEDExample/LLN0.svcb");
	request.list[0].setFlag[SET_MSVCB_FLAG_SV_ENA] = 1;
	request.list[0].svEna = FALSE;

	result = IEC61850_SetMSVCBValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n");
		PrintSetMSVCBValues(&request);
		printf("response:\n");
		PrintSetMSVCBValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeSetMSVCBValues_Response(&response);

	// free the dynamically allocated memory of 'request'.
	free(request.list);

	return result;
}

IEC61850_ErrorCode SelectActiveSG()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	SelectActiveSG_Request request = { 0 };
	SelectActiveSG_Response response = { 0 };

	char userInput[256] = { 0 };
	char* sgcbRef = "ServerIEDExample/LLN0.SGCB";
	U8 sgNum = 0;
	setbuf(stdin, NULL);
	while (sgNum > 5 || sgNum < 1) {
		memset(userInput, 0, 256);
		printf("please select ActiveSG number [1-5] for [%s]: ", sgcbRef);
		if (fgets(userInput, sizeof(userInput), stdin) != NULL) {
			sgNum = atoi(userInput);
		}
	}

	request.sgcbReference = sgcbRef;
	request.settingGroupNumber = sgNum;

	result = IEC61850_SelectActiveSG(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n\tsgcbReference: [%s]\n\tsettingGroupNumber: [%u]\n", request.sgcbReference, request.settingGroupNumber);
		printf("response:\n");
		PrintSelectActiveSGResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	return result;
}

IEC61850_ErrorCode SelectEditSG()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	SelectEditSG_Request request = { 0 };
	SelectEditSG_Response response = { 0 };

	char userInput[256] = { 0 };
	char* sgcbRef = "ServerIEDExample/LLN0.SGCB";
	U8 sgNum = 0;
	setbuf(stdin, NULL);
	while (sgNum > 5 || sgNum < 1) {
		memset(userInput, 0, 256);
		printf("please select EditSG number [1-5] for [%s]: ", sgcbRef);
		if (fgets(userInput, sizeof(userInput), stdin) != NULL) {
			sgNum = atoi(userInput);
		}
	}

	request.sgcbReference = sgcbRef;
	request.settingGroupNumber = sgNum;

	result = IEC61850_SelectEditSG(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n\tsgcbReference: [%s]\n\tsettingGroupNumber: [%u]\n", request.sgcbReference, request.settingGroupNumber);
		printf("response:\n");
		PrintSelectEditSGResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	return result;
}

IEC61850_ErrorCode SetEditSGValue()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	SetEditSGValue_Request request = { 0 };
	SetEditSGValue_Response response = { 0 };
	unsigned int i = 0;
	unsigned int index = 0;
	S32 newVal = 0;
	DataRefValue dataList[1] = { 0 };
	char* reference = "";
	char arrayRef[3][129] = {
		"ServerIEDExample/IARC0.MaxNumRcd.setVal",
		"ServerIEDExample/IARC0.OpMod.setVal",
		"ServerIEDExample/IARC0.MemFull.setVal"
	};
	printf("SG data reference list:\n");
	for (i = 0; i < 3; i++) {
		printf("  %d. %s\n", i + 1, arrayRef[i]);
	}
	printf("Please select a SG data to edit: \n");
	index = GetIndexFromUser();
	if (index >= 1 || index <= 3) {
		reference = (char*)&(arrayRef[index - 1]);
	}

	printf("\nPlease set a new value.\n");
	newVal = GetInteger32FromUser();

	dataList[0].dataRef = reference;
	dataList[0].dataAttribute.type = IEC61850_DATATYPE_INT32;
	dataList[0].dataAttribute.bitLength = 32;
	dataList[0].dataAttribute.pvData = &newVal;

	request.data.length = 1;
	request.data.dataRefValueList = dataList;

	result = IEC61850_SetEditSGValue(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n");
		for (i = 0; i < request.data.length; i++) {
			printf("\tdata(%u):\n\t  reference: [%s]\n\t  value:\n", i + 1, request.data.dataRefValueList[i].dataRef);
			PrintDataValue(&(request.data.dataRefValueList[i].dataAttribute), 2, FALSE);
		}
		printf("response:\n");
		PrintSetEditSGValueResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeSetEditSGValue_Response(&response);
	return result;
}

IEC61850_ErrorCode ConfirmEditSGValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	ConfirmEditSGValues_Request request = { 0 };
	ConfirmEditSGValues_Response response = { 0 };

	request.sgcbReference = "ServerIEDExample/LLN0.SGCB";
	result = IEC61850_ConfirmEditSGValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n\tsgcbReference: [%s]\n", request.sgcbReference);
		printf("response:\n");
		PrintConfirmEditSGValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	return result;
}

IEC61850_ErrorCode GetEditSGValue()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetEditSGValue_Request request = { 0 };
	GetEditSGValue_Response response = { 0 };
	char ref[3][OBJECT_REFERENCE_STRING_LEN] = {
		"ServerIEDExample/IARC0.MaxNumRcd.setVal",
		"ServerIEDExample/IARC0.OpMod.setVal",
		"ServerIEDExample/IARC0.MemFull.setVal"
	};
	FCDA fcda[3] = { 0 };
	char userInput[256] = { 0 };
	unsigned int i = 0;

	printf("please select:\n1. GetEditSGValue [FC=SG]\n2. GetEditSGValue [FC=SE]\ninput the index: ");
	memset(userInput, 0, 256);
	setbuf(stdin, NULL);
	if (fgets(userInput, sizeof(userInput), stdin) != NULL) {
		switch (userInput[0]) {
		case '1':
			for (i = 0; i < 3; i++) {
				strncpy(fcda[i].FC, "SG", 3);
			}
			break;
		case '2':
			for (i = 0; i < 3; i++) {
				strncpy(fcda[i].FC, "SE", 3);
			}
			break;
		}
	}
	for (i = 0; i < 3; i++) {
		strncpy(fcda[i].DARef, ref[i], OBJECT_REFERENCE_STRING_LEN + 1);
		fcda[i].DARef[OBJECT_REFERENCE_STRING_LEN] = '\0';
	}

	request.data.size = 3;
	request.data.FCDAs = fcda;

	result = IEC61850_GetEditSGValue(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n");
		PrintFCDAList(&request.data);
		printf("response:\n");
		PrintGetEditSGValueResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetEditSGValue_Response(&response);
	return result;
}

IEC61850_ErrorCode GetSGCBValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetSGCBValues_Request request = { 0 };
	GetSGCBValues_Response response = { 0 };

	request.sgcbReference = StringListMalloc();
	if (request.sgcbReference == NULL) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	StringListAdd(request.sgcbReference, "ServerIEDExample/LLN0.SGCB");

	result = IEC61850_GetSGCBValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		unsigned int i = 0;
		printf("request:\n");
		for (i = 0; i < request.sgcbReference->length; i++) {
			printf("\tsgcbReference[%d]: [%s]\n", i + 1, request.sgcbReference->list[i]);
		}
		printf("response:\n");
		PrintGetSGCBValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetSGCBValues_Response(&response);
	FreeStringList(request.sgcbReference);
	return result;
}

IEC61850_ErrorCode CMSGetFile()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetFile_Request request = { 0 };
	GetFile_Response response = { 0 };

	char remoteFileName[256] = { 0 };
	char localFileName[256] = { 0 };

	GetFileNameFromUser("Enter the remote source file name to get. (should start with \"/\"): ", remoteFileName);
	GetFileNameFromUser("Enter the local destination file name: ", localFileName);

	result = IEC61850_GetFile(iec61850, serverIndex, remoteFileName, localFileName);

	if (result != S_OK) {
		printf("result:[%d]\n", result);
	}

	return result;
}

IEC61850_ErrorCode CMSSetFile()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	char remoteFileName[256] = { 0 };
	char localFileName[256] = { 0 };

	GetFileNameFromUser("Enter the local source file name: ", localFileName);
	GetFileNameFromUser("Enter the remote destination file name to set. (should start with \"/\"): ", remoteFileName);
	result = IEC61850_SetFile(iec61850, serverIndex, localFileName, remoteFileName);
	if (result != S_OK) {
		printf("result:[%d]\n", result);
	}
	return result;
}

IEC61850_ErrorCode CMSDeleteFile()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;

	eServiceError serviceError = SERVICE_ERROR_NO_ERROR;
	char fileName[VISIBLE_STRING_255_LEN + 1] = { 0 };
	GetFileNameFromUser("Enter the file name for deletion. (should start with \"/\"): ", fileName);

	result = IEC61850_DeleteFile(iec61850, serverIndex, fileName, &serviceError);
	if (result == S_OK) {
		printf("request:\n\tfilename: [%s]\n", fileName);
		if (serviceError == SERVICE_ERROR_NO_ERROR) {
			printf("response:\nResponse+\n");
		} else {
			printf("response:\nResponse-\n\tServiceError: (%d) %s\n", serviceError, TranslateServiceError(serviceError));
		}
	} else {
		printf("result:[%d]\n", result);
	}

	return result;
}

IEC61850_ErrorCode CMSGetFileAttributeValues()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetFileAttributeValues_Request request = { 0 };
	GetFileAttributeValues_Response response = { 0 };

	char fileName[VISIBLE_STRING_255_LEN + 1] = { 0 };
	GetFileNameFromUser("Enter the file name. (should start with \"/\"): ", fileName);

	strncpy(request.fileName, fileName, VISIBLE_STRING_255_LEN);

	result = IEC61850_GetFileAttributeValues(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n");
		printf("\tfilename: [%s]\n", request.fileName);
		printf("response:\n");
		PrintGetFileAttributeValuesResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetFileAttributeValues_Response(&response);
	return result;
}

IEC61850_ErrorCode CMSGetFileDirectory()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetFileDirectory_Request request = { 0 };
	GetFileDirectory_Response response = { 0 };
	char fileAfter[VISIBLE_STRING_255_LEN + 1] = { 0 };
	char pathName[VISIBLE_STRING_255_LEN + 1] = { 0 };
	GetFileNameFromUser("Enter the file path. (should start with \"/\"): ", pathName);
	if (strlen(pathName) != 0) {
		strncpy(request.pathName, pathName, VISIBLE_STRING_255_LEN);
	} else {
		strcpy(request.pathName, "/");
	}

	request.startTime = calloc(1, sizeof(IEC61850_TimeStamp));
	if (request.startTime) {
		IEC61850_GetIEC61850TimeFromDate(request.startTime, 1, 20, 2020, 12, 34, 56, 789012);	// 2020-01-20 12:34:56.789012
	}

	request.stopTime = calloc(1, sizeof(IEC61850_TimeStamp));
	if (request.stopTime) {
		IEC61850_GetTime(iec61850, request.stopTime);
	}

	GetFileNameFromUser("Enter the fileAfter: ", fileAfter);
	if (strlen(fileAfter) != 0) {
		fileAfter[VISIBLE_STRING_255_LEN] = '\0';
		request.fileAfter = (char*)&fileAfter;
	}

	result = IEC61850_GetFileDirectory(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n");
		printf("\tpathName:  [%s]\n", request.pathName);
		if (request.startTime) {
			printf("\tstartTime: ");
			PrintTimeStamp(request.startTime);
		}
		if (request.stopTime) {
			printf("\tstopTime:  ");
			PrintTimeStamp(request.stopTime);
		}
		if (request.fileAfter) {
			printf("\tfileAfter: [%s]\n", request.fileAfter);
		}
		printf("response:\n");
		PrintGetFileDirectoryResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetFileDirectory_Response(&response);

	// free the dynamically allocated memory of 'request'.
	if (request.startTime) {
		free(request.startTime);
	}
	if (request.stopTime) {
		free(request.stopTime);
	}

	return result;
}

IEC61850_ErrorCode GetRpcInterfaceDirectory()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetRpcInterfaceDirectory_Request request = { 0 };
	GetRpcInterfaceDirectory_Response response = { 0 };

	result = CMS_GetRpcInterfaceDirectory(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		if (request.referenceAfter) {
			printf("request:\n");
			printf("\treferenceAfter: [%s]\n", request.referenceAfter);
		}
		printf("response:\n");
		PrintGetRpcInterfaceDirectoryResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetRpcInterfaceDirectory_Response(&response);

	return result;
}

IEC61850_ErrorCode GetRpcMethodDirectory()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetRpcMethodDirectory_Request request = { 0 };
	GetRpcMethodDirectory_Response response = { 0 };

	request.sInterface = "InterfaceName1";
	request.referenceAfter = "I1_Method1";

	result = CMS_GetRpcMethodDirectory(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n");
		printf("\tinterface:      [%s]\n", request.sInterface);
		printf("\treferenceAfter: [%s]\n", request.referenceAfter);
		printf("response:\n");
		PrintGetRpcMethodDirectoryResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetRpcMethodDirectory_Response(&response);
	return result;
}

IEC61850_ErrorCode GetRpcInterfaceDefinition()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetRpcInterfaceDefinition_Request request = { 0 };
	GetRpcInterfaceDefinition_Response response = { 0 };

	request.sInterface = "InterfaceName1";
	request.referenceAfter = "I1_Method1";

	result = CMS_GetRpcInterfaceDefinition(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n");
		printf("\tinterface:      [%s]\n", request.sInterface);
		if (request.referenceAfter) {
			printf("\treferenceAfter: [%s]\n", request.referenceAfter);
		}
		printf("response:\n");
		PrintGetRpcInterfaceDefinitionResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetRpcInterfaceDefinition_Response(&response);

	return result;
}

IEC61850_ErrorCode GetRpcMethodDefinition()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	GetRpcMethodDefinition_Request request = { 0 };
	GetRpcMethodDefinition_Response response = { 0 };

	unsigned int uiRefNum = 4;
	request.reference.length = uiRefNum;
	request.reference.list = calloc(uiRefNum, sizeof(char*));
	if (request.reference.list == NULL) {
		return IEC61850_ERROR_NO_MEMORY;
	}

	request.reference.list[0] = "InterfaceName1.I1_Method1";
	request.reference.list[1] = "InterfaceName1.I1_Method2";
	request.reference.list[2] = "InterfaceName1.I1_Method3";
	request.reference.list[3] = "InterfaceName1.I1_Method4";

	result = CMS_GetRpcMethodDefinition(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		unsigned int i = 0;
		printf("request:\n");
		for (i = 0; i < request.reference.length; i++) {
			printf("\treference[%u]: [%s]\n", i + 1, request.reference.list[i]);
		}
		printf("response:\n");
		PrintGetRpcMethodDefinitionResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeGetRpcMethodDefinition_Response(&response);

	// free the dynamically allocated memory of 'request'.
	free(request.reference.list);

	return result;
}

IEC61850_ErrorCode RpcCall()
{
	IEC61850_ErrorCode result = S_OK;
	IEC61850 iec61850 = GetMyServerClient();
	unsigned int serverIndex = 0;
	RpcCall_Request request = { 0 };
	RpcCall_Response response = { 0 };
	U32 dataVal = 3;

	request.method = "InterfaceName1.I1_Method1";
	request.reqData.eDataType = DATA_TYPE_INT32U;
	request.reqData.pvData = &dataVal;

	result = CMS_RpcCall(iec61850, serverIndex, &request, &response);
	if (result == S_OK) {
		printf("request:\n");
		printf("  method: [%s]\n", request.method);
		printf("  req: ");
		if (request.callID) {
			printf("callID: [%s]\n", request.callID);
		} else {
			printf("reqData: \n");
			PrintCMSData(&request.reqData, 2, FALSE);
		}
		printf("response:\n");
		PrintRpcCallResponse(&response);
	} else {
		printf("result:[%d]\n", result);
	}
	FreeRpcCall_Response(&response);

	return result;
}

IEC61850_ErrorCode Discover(U32 type)
{
	IEC61850_ErrorCode result = S_OK;

	int serverIndex = 0;
	IEC61850 iec61850 = GetMyServerClient();
	ConnectionList connections = { 0 };
	char ipaddr[256] = { 0 };
	FILE* file = NULL;

	GetServerDirectory_Request req_sd = { 0 };
	GetServerDirectory_Response res_sd = { 0 };
	StringList* ieds = NULL;

	result = IEC61850_GetConnectionsList(iec61850, &connections);
	if (result != S_OK || connections.length == 0) {
		printf("\n\tConnect failed:\n");
		return result;
	}

	snprintf(ipaddr, 255, "%s.txt", connections.connections[serverIndex].IPAddress);
	file = fopen(ipaddr, "w+");
	if (!file) {
		return IEC61850_ERROR_INVALID_PARAMETERS;
	}

	res_sd.reference = StringListMalloc();
	result = IEC61850_GetServerDirectory(iec61850, serverIndex, &req_sd, &res_sd);
	if (result == S_OK) {
		if (res_sd.serviceError == SERVICE_ERROR_NO_ERROR) {
			ieds = res_sd.reference;
		}
		PrintGetServerDirectoryResponse(&res_sd);
	}

	if (ieds) {
		U32 iedIndex = 0;
		for (iedIndex = 0; iedIndex < ieds->length; iedIndex++) {
			char* ldRef = ieds->list[iedIndex];
			char referenceAfter[129] = { 0 };
			Boolean moreFollows = TRUE;

			fprintf(file, "[LD] = %s\n", ldRef);

			if (type == 1) { // ASCI
				int indexAcsi = 0;
				struct ASCI_DESC {
					IEC61850_ACSIClass acsiClass;
					char* name;
				} acsiTypes[] = {
					{ACSI_CLASS_DATA_OBJECT, "DataObject"},	{ACSI_CLASS_DATA_SET, "Dataset"},
					{ACSI_CLASS_BRCB, "BRCB"}, {ACSI_CLASS_URCB, "URCB"},
					{ACSI_CLASS_LCB, "LCB"}, {ACSI_CLASS_LOG, "LOG"},
					{ACSI_CLASS_SGCB, "SGCB"}, {ACSI_CLASS_GoCB, "GoCB"},
					{ACSI_CLASS_MSVCB, "MSVCB"},
				};

				for (indexAcsi = 0; indexAcsi < sizeof(acsiTypes) / sizeof(struct ASCI_DESC); indexAcsi++) {
					moreFollows = TRUE;
					memset(referenceAfter, 0, sizeof(referenceAfter));

					fprintf(file, "[%s]\n", acsiTypes[indexAcsi].name);
					while (moreFollows) {
						GetLogicalNodeDirectory_Request  req_ln = { 0 };
						GetLogicalNodeDirectory_Response res_ln = { 0 };
						req_ln.acsiClass = acsiTypes[indexAcsi].acsiClass;
						req_ln.reference = ldRef;

						if (strlen(referenceAfter) != 0) {
							req_ln.referenceAfter = referenceAfter;
						}

						result = IEC61850_GetLogicalNodeDirectory(iec61850, serverIndex, &req_ln, &res_ln);
						if (result == S_OK) {
							PrintGetLogicalNodeDirectoryResponse(&res_ln);
							if (res_ln.reference){
								unsigned int index = 0;
								for (index = 0; index < res_ln.reference->length; index++) {
									fprintf(file, "\t%s/%s\n", ldRef, res_ln.reference->list[index]);
								}
							}
						}

						moreFollows = res_ln.moreFollows;
						if (moreFollows) {
							strncpy(referenceAfter, res_ln.reference->list[res_ln.reference->length - 1], 129);
						}
						FreeGetLogicalNodeDirectory_Response(&res_ln);
					}
				}
			} else if (type == 2) { // AllDefinition
				memset(referenceAfter, 0, sizeof(referenceAfter));
				moreFollows = TRUE;
				while (moreFollows) {
					GetAllData_Request req_ad = { 0 };
					GetAllDataDefinition_Response res_ad = { 0 };

					if (strlen(referenceAfter) != 0) {
						req_ad.referenceAfter = referenceAfter;
					}

					req_ad.reference = ldRef;
					req_ad.fc = "XX";
					result = IEC61850_GetAllDataDefinition(iec61850, serverIndex, &req_ad, &res_ad);
					if (result == S_OK) {
						U32 i = 0;
						int j = 0;
						PrintGetAllDataDefinitionResponse(&res_ad);
						for (i = 0; i < res_ad.data.length; i++) {
							DataRefDefinition* dataRefDef = &res_ad.data.dataRefDefinitionList[i];
							fprintf(file, "\t%s/%s\n", ldRef, dataRefDef->dataRef);
							for (j = 0; j < dataRefDef->definition.structSize; j++) {
								struct StructDefinition* sd = &dataRefDef->definition.structDefinition[j];
								fprintf(file, "\t%s/%s.%s\n", ldRef, dataRefDef->dataRef, sd->name);
							}
						}
					}

					moreFollows = res_ad.moreFollows;
					if (moreFollows) {
						strncpy(referenceAfter, res_ad.data.dataRefDefinitionList[res_ad.data.length - 1].dataRef, 129);
					}
					FreeDataDefinitions(&res_ad.data);
				}
			}
		}
	}
	
	FreeGetServerDirectory_Response(&res_sd);
	fclose(file);

	getchar();

	return result;
}

IEC61850_ErrorCode InnerTestClient()
{
	return S_OK;
}

IEC61850_ErrorCode InnerTestServer()
{
	return S_OK;
}